<template>
	<view>
    <view class="upload-top">
      <view v-if="connectedDeviceName">当前已连接设备</view>
      <view v-else class="warning" @click="toConnect">没有连接设备</view>
      <view>{{connectedDeviceName}}</view>
    </view>
    <divider></divider>
    <view class="upload-middle">
      <button class="first-button" type="primary" @click="uploadHot">热熔记录上传</button>
      <button type="primary" disabled="true">电熔记录上传</button>
    </view>
    <view class="upload-bottom">
      <view class="upload-bottom-title">
        <div class="image-box">
          <image src="/static/image/upload/warning.png"></image>
        </div>
        <text>温馨提示</text>
      </view>
      <view class="upload-bottom-content">
        <text>1、此页面上传焊接记录，针对的是无物联网卡的设备。有物联网卡的设备会在焊接后自动上传焊接记录。</text>
        <text>2、电熔记录上传通道尚未开启，目前暂时无法上传电熔记录。</text>
      </view>
    </view>
    <modal v-model="showModalForConnect" confirm-style="color: #DC2115" title='询问'
           text='当前尚未连接设备，请先进行连接' @cancel='cancelConnect' @confirm='toConnect'></modal>
    <modal v-model="showModalForLoading" confirm-style="color: #DC2115" title='提示'
           :text='loadingText' @cancel='cancelUpload' no-confirm></modal>
    <message ref="message"></message>
	</view>
</template>

<script>

  import divider from "../../components/divider";
  import store from '@/store/index.js'
  import {readCommands, recordRaw, clearData} from "../../js/interaction";
  // import {readCommands, interactionHexData, clearData} from "../../js/interaction";
  import {uploadHot} from "../../api/upload/upload";
  import {formatDate} from "../../js/common";

  let readInterval = 300; // 读取完记录中数据后的休眠时间
  let recordInterval = 3000 // 读取完记录后的休眠时间
  export default {
		data() {
			return {
        connectedDeviceName: '',
        showModalForConnect: false,
        showModalForLoading: false,
        // timerRecord: null, // 读取记录时开启的定时器
        // timerRecordData: null, // 分多次读取单条记录时开启的定时器
        count: 0,
        isReadingRecord: false, // 当前是否在读记录
        // isReadingRecordData: false, // 当前是否在读记录中的数据，这个已经放到store里了
        startRecord: null,
        startRecordData: null,
        isSleepingRecord: false, // 已经读取完记录，但是正处于睡眠中
        isSleepingRecordData: false, // 已经读取完记录中的数据，但是正处于睡眠中
        // timerParse: null, // 解析记录时开启的定时器
        isParseIndicator: false, // 是否正在解析记录
        errorUploadCount: 0, // 上传同一条记录时失败的次数，到达3次就结束上传
			}
		},
    computed: {
      loadingText() {
        return `当前还剩${this.count - store.state.blueTooth.recordIndex}条记录未读取，请耐心等待`;
      }
    },
		methods: {
      /**
       * 上传热熔记录
       */
      uploadHot() {
        // 如果没有连接设备，那么先去连接设备
        if (!this.connectedDeviceName) {
          this.showModalForConnect = true;
        } else {
          this.writeToBlueTooth();
          this.showModalForLoading = true;
          store.commit('clearRecordIndex')
        }
        // this.writeToBlueTooth();
        // this.showModalForLoading = true;
        // store.commit('clearRecordIndex')
      },
      /**
       * 点击确认跳转到连接设备的界面
       */
      toConnect() {
        uni.navigateTo({
          url: '/pages/connect/connect'
        })
      },
      /**
       * 点击取消，上传失败
       */
      cancelConnect() {
        this.$refs.message.error('上传记录失败')
      },
      /**
       * 取消上传
       */
      cancelUpload() {
        store.commit('stopAllTimer')
        this.showModalForLoading = false;
        this.isReadingRecord = false;
        this.isParseIndicator = false;
        store.commit('setReadRecordDataFalse')
      },
      /**
       * 从蓝牙中写命令
       */
      writeToBlueTooth() {
        this.showModalForLoading = false;
        this.isReadingRecord = false;
        this.isParseIndicator = false;
        this.errorUploadCount = 0;
        store.commit('setReadRecordDataFalse')
        store.commit('clearRecordIndex')
        store.commit('clearReadIndex')
        // 获取有多少条记录未读
        this.getCountFromBlueTooth();
        // 没有记录的情况
        if (this.count === 0) {
          this.showModalForLoading = false;
          this.$refs.message.info("该设备没有记录可供上传");
          return;
        }
        this.isReadingRecord = false;
        // 有记录的情况
        this.readRecordFromBlueTooth();
      },
      /**
       * 读取所有记录
       */
      readRecordFromBlueTooth() {
        // 3秒去看一下记录有没有读好
        // 因为读取完一条记录后，要等待3秒时间才能读取下一条记录
        this.readRecordFromBlueToothLogic();
        this.timerRecord = setInterval(() => {
          this.readRecordFromBlueToothLogic();
        }, 100)
      },
      readRecordFromBlueToothLogic() {
        // 保存到store里
        store.commit("setTimerRecord", this.timerRecord);
        // 判断是否在读，在读的话就不执行下面的逻辑
        if (!this.isReadingRecord) {
          // 设置当前在读
          this.isReadingRecord = true;
          // 获取已经读了多少条记录了
          let recordIndex = store.state.blueTooth.recordIndex;
          console.log(recordIndex);
          // 如果已经读的记录和这里的count相等，那么就表示所有记录已经读取完毕
          if (recordIndex === this.count) {
            // 关闭本定时器
            clearInterval(this.timerRecord);
            // 关闭弹窗
            this.showModalForLoading = false;
            this.$refs.message.success("记录全部上传成功！");
            // 结束方法
            return;
          }
          // 如果还有没有读取记录的话会走这里的分支
          // 首先先清掉store中的readIndex，让下一条记录读取时也从readIndex值为0开始
          // TODO 生产环境不需要以下两行代码
          // store.commit('clearReadIndex');
          // clearData();
          // 调用方法去读下一条记录
          this.readOneRecordFromBlueTooth();
        }
      },
      /**
       * 读取单条记录
       */
      readOneRecordFromBlueTooth() {
        // console.log(store.state.blueTooth.isReadingRecordData)
        // 获取recordIndex，在这里获取这个值只是为了打印的需要
        let recordIndex = store.state.blueTooth.recordIndex;
        // 300毫秒给蓝牙发送一次读取命令
        // 每隔300毫秒写入一次读取指令可以保证接收数据的时候不冲突
        this.readOneRecordFromBlueToothLogic(recordIndex)
        this.timerRecordData = setInterval(() => {
          this.readOneRecordFromBlueToothLogic(recordIndex)
        }, 100)
      },
      readOneRecordFromBlueToothLogic(recordIndex) {
        store.commit("setTimerRecordData", this.timerRecordData);
        // 获取当前读到第几条命令了（这里用的索引，值为第几条-1）
        let readIndex = store.state.blueTooth.readIndex;
        console.log(`读取第${recordIndex + 1}条记录`)
        // 当读完最后一条命令后，关闭定时器（读完一条readIndex+1，然后读完最后一条时，值正好是readCommands的长度）
        console.log("============" + readIndex);
        let isReadingRecordData = store.state.blueTooth.isReadingRecordData;
        if (!isReadingRecordData) {
          store.commit("setReadRecordDataTrue")
          // this.isReadingRecordData = true;
          if (readIndex === readCommands.length) {
            // 关闭本方法的定时器
            clearInterval(this.timerRecordData);
            // // 将isReadingRecord置为false，表示当前不再读。
            // // 这样执行上一个方法的定时器时，就会走到第一个if里面
            // this.isReadingRecord = false;
            // 开始解析记录，并将其上传
            // this.parseLogic(recordIndex);
            this.timerParse = setInterval(() => {
              this.parseLogic(recordIndex);
            }, 1000)
            return;
          }
          console.log(`读取第${recordIndex + 1}条的第${readIndex + 1}记录开始`)
          // 发送读取数据的指令
          this.doReadOneIndicator(readCommands[readIndex], recordIndex, readIndex);
        }
      },
      parseLogic(recordIndex) {
        store.commit("setTimerParse", this.timerParse)
        console.log(this.isParseIndicator?'在解析':'不在解析');
        if (!this.isParseIndicator) {
          this.isParseIndicator = true;
          // 解析读到的指令
          this.interactionHexData(recordIndex);
        }
      },
      /**
       * 解析十六进制数据
       * @param hex 待解析的十六进制数据
       */
      interactionHexData(recordIndex) {
        // 1.解析
        let record = this.doInteractionHexData();
        if (!record) {
          return;
        }
        // 2.上传记录
        this.doUploadHot(record, recordIndex);
      },
      /**
       * 真正的记录上传操作
       * @param record 记录信息
       * @param recordIndex 读到第几条数据，该参数只做显示，没有逻辑上的用途
       */
      doUploadHot(record, recordIndex) {
        uploadHot(record).then(res => {
          console.log(res);
          if (res.data.code === 200) {
            // 3.上传完清空
            // TODO 这里还少一步发送指令让机器去读下一条记录
            clearInterval(this.timerParse);
            store.commit('clearReadIndex')
            clearData();
            // 清空上传的错误次数
            this.errorUploadCount = 0;
            // 将isReadingRecord置为false，表示当前不再读。
            // 这样执行就会在定时器执行readRecordFromBlueToothLogic方法时，走到第一个if里面
            setTimeout(() => {
              this.isReadingRecord = false;
              // this.isReadingRecordData = false;
              store.commit("setReadRecordDataFalse")
              this.isParseIndicator = false;
              // 自增recordIndex，表示本条已经读完
              store.commit('incrementRecordIndex')
            }, recordInterval)
            console.log(`第${recordIndex + 1}条记录已经读取完毕`)
          } else {
            this.$refs.message.error("数据有误，上传失败");
            this.cancelUpload(); // 数据有问题，停止上传
          }
        }).catch(err => {
          console.log(err);
          this.errorUploadCount++;
          if (this.errorUploadCount >= 3) {
            this.cancelUpload();
            this.$refs.message.error("网络超时，操作被中断");
            return;
          }
          // 递归调用
          setTimeout(() => {
            this.doUploadHot(record, recordIndex)
          }, 200)
        })
      },
      /**
       * 真正解析十六进制数据，将其解析为记录对象
       * TODO 没有真正的完成，只解析了前面三个数据
       */
      doInteractionHexData() {
        console.log("解析数据，当前数据为：" + recordRaw);
        if (recordRaw) {
          let remainHex = recordRaw;
          // 1.处理功能码（占1个地址位，即2个字节，即4位十六进制）
          let codeHex = remainHex.substring(0, 4);
          let code = parseInt(codeHex, 16);
          remainHex = remainHex.substring(4, remainHex.length);
          console.log("功能码为："+ code + "。处理完功能码后，剩余的数据为：" + remainHex);

          // 2.处理数据长度（占1个地址位，即2个字节，即4位十六进制）
          let lengthHex = remainHex.substring(0, 4);
          let length = parseInt(lengthHex, 16);
          remainHex = remainHex.substring(4, remainHex.length);
          console.log("数据长度为："+ length + "。处理完数据长度后，剩余的数据为：" + remainHex);

          // 3.处理机器编号（占2个地址位，即4个字节，即8位十六进制）
          let machineIdHex = remainHex.substring(0, 8);
          let machineId = parseInt(machineIdHex, 16);
          remainHex = remainHex.substring(4, remainHex.length);
          console.log("机器编号为："+ machineId + "。处理完机器编号后，剩余的数据为：" + remainHex);

          // TODO 4.处理其他字段，现阶段写死
          let record = {}
          record.MachineId = machineId + "";
          record.WelderID = "12345609";
          record.ProjectID = "ABCDEFGHIJK19837865";
          record.ManagerID = "cao_qilong";
          record.ManufactureID = 'wxsd';
          record.RecordNum = 0;
          record.WeldNum = 994;
          record.standard = "0";
          record.machineModel = "250";
          record.SDR = 11;
          record.Material = 100;
          record.Diameter = 110;
          record.ReplaceMachineID = 0;
          record.Appearance = 0;
          record.Result = 1;
          record.IsTimeValid = true;
          record.userCode = 0;
          record.RecordTime = formatDate(new Date());
          record.Latitude = 103.943623352051;
          record.Longitude = 30.6503016789754;
          record.PhoneNumber = "15211112222";
          record.CylinderArea = 11.0;
          record.DragPressure = 12.5;
          record.SetWeldTemp = 225;
          record.ActWeldTemp = 223;
          record.SetFlangingPressure = 16.8;
          record.ActFlangingPressure = 16.8;
          record.SetFlangingTime = 20;
          record.ActFlangingTime = 20;
          record.SetAbsorbHeatPressure = 0;
          record.ActAbsorbHeatPressure = 0.1;
          record.SetAbsorbHeatTime = 100;
          record.ActAbsorbHeatTime = 100;
          record.SwitchingPeriod = 3
          record.BoostPressurePeriod = 3;
          record.SetJointPressure = 16.8;
          record.ActJointPressure = 15.3;
          record.SetCoolingTime = 840;
          record.ActCoolingTime = 840;
          return record;
        }

      },
      /**
       * 发送单条读取指令
       * @param indicator 指令内容
       */
      doReadOneIndicator(indicator, recordIndex, readIndex) {
        uni.writeBLECharacteristicValue({
          // 这里的 deviceId 需要在 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
          deviceId: store.state.blueTooth.connectedDevice.deviceId,
          // 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
          serviceId: store.state.blueTooth.connectedDevice.serviceId,
          // 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
          characteristicId: store.state.blueTooth.connectedDevice.characteristicId,
          // 这里的value是ArrayBuffer类型
          value: this.str2ab(indicator),
          success: res => {
            console.log('writeBLECharacteristicValue success', res.errMsg);
            // 等待300毫秒将isReadingRecordData置为false，
            // 让readOneRecordFromBlueToothLogic方法可以走第一个if语句，即继续写下一条读取指令
            // setTimeout(() => {
            //   this.isReadingRecordData = false;
            //   console.log(`读取第${recordIndex + 1}条的第${readIndex + 1}记录完毕`)
            // }, 3000)
          },
          fail: err => {
            console.log(err);
            store.commit('setReadRecordDataFalse')
            // this.isReadingRecordData = false;
          }
        })
      },
      /**
       * 从蓝牙设备中获取还有几条数据要读
       */
      getCountFromBlueTooth() {
        store.commit('setRecordIndex', 0);
        // TODO 获取还剩多少条记录没有读
        this.count = 1
        // this.count = 10;
      },
      /**
       * 将十六进制的字符串转化成蓝牙可发送的数据
       * @param str
       * @returns {ArrayBuffer}
       */
      str2ab(str) {
        let buf = new ArrayBuffer(str.length / 2);
        let bufView = new Uint8Array(buf);
        for (let i = 0; i < str.length / 2; i++) {
          // bufView[i] = str.charCodeAt(i);
          // bufView[i] = '0x' + (str[i * 2] + str[i * 2 + 1]);
          bufView[i] = '0x' + (str.charAt(i * 2) + str.charAt(i * 2 + 1));
          // console.log(bufView[i]);
        }
        return buf
      },
		},
    components: {
		  divider
    },
    onShow() {
		  this.connectedDeviceName = store.state.blueTooth.connectedDevice.name;
		  console.log(formatDate(new Date()))
    },
    onReady() {
      this.$refs.message.setMessageToStore(this.$refs.message)
    }
	}
</script>

<style scoped lang="scss">
  @import "~@/static/css/upload.scss";
</style>
